#ifndef __LS_ASYNCWORKER_H__
#define __LS_ASYNCWORKER_H__

#include "buffer.hpp"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <memory>

namespace log_system
{
    using Callback = std::function<void(Buffer&)>;
    enum class AsyncWorkerType
    {
        ASYNC_SAFE,     //安全状态，缓冲区满则阻塞，避免资源耗尽的风险
        ASYNC_UNSAFE    //不考虑资源耗尽的风险，无限扩容
    };

    class AsyncWorker
    {
    public:
        using ptr = std::shared_ptr<AsyncWorker>;

        AsyncWorker(const Callback& cb, AsyncWorkerType type = AsyncWorkerType::ASYNC_SAFE):
            _callback(cb),
            _type(type),
            _stop(false),
            _thread(std::thread(&AsyncWorker::threadEntry, this))
        {}

        ~AsyncWorker()
        {
            stop();
        }



        void push(const char* data, size_t len)
        {
            // 1.无限扩容，非安全模式  2.固定大小，生产缓冲区满则阻塞
            std::unique_lock<std::mutex> lock(_mutex);
            // 安全模式下，若缓冲区剩余空间大小大于数据长度，则可以添加数据
            if(_type == AsyncWorkerType::ASYNC_SAFE)
                _pro_cv.wait(lock, [&](){ return _pro_buf.writableSize() >= len; });
            _pro_buf.push(data, len);
            // 唤醒消费者对缓冲区中的数据做处理
            _con_cv.notify_one();            

        }
    private:

        void stop()
        {
            _stop = true;
            _con_cv.notify_all();//唤醒工作线程
            _thread.join();//等待工作线程的退出
        }
        
        void threadEntry()
        {
            while(true)
            {
                {
                    //1.判断生产缓冲区有无数据，有则交换，无则阻塞
                    std::unique_lock<std::mutex> lock(_mutex);

                    //若因退出被唤醒或生产缓冲区有数据被唤醒，则继续向后运行，否则阻塞休眠
                    _con_cv.wait(lock, [&](){ return _stop || !_pro_buf.empty(); });

                    //退出标志被设置，生产缓冲区已无数据，才退出。
                    if(_stop && _pro_buf.empty()) break;

                    _con_buf.swap(_pro_buf);
                    
                    //2.唤醒生产者(安全状态才可能由于生产缓冲区满而阻塞)
                    if(_type == AsyncWorkerType::ASYNC_SAFE)
                        _pro_cv.notify_all();
                }
                //3.被唤醒后，对消费缓冲区进行处理
                _callback(_con_buf);
                //4.初始化消费缓冲区
                _con_buf.reset();
            }
        }


    private:
        Callback _callback; //具体对缓冲区数据进行处理的回调函数，由异步工作器使用者传入。
    private:
        AsyncWorkerType _type;
        bool _stop; //工作器停止标志
        Buffer _pro_buf;
        Buffer _con_buf;
        std::mutex _mutex;
        std::condition_variable _pro_cv;
        std::condition_variable _con_cv;
        std::thread _thread;

    };
}

#endif